package com.ruleengine.task.config;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;

import com.ruleengine.compiler.ITaskCompiler;
import com.ruleengine.parser.ITaskParser;
import com.ruleengine.task.ITask;
import com.ruleengine.task.TaskType;
import com.ybt.configration.IYBTConfigration;
import com.ybt.configration.YBTConfigration;
import com.ybt.configration.YBTRuntimeConfiguration;
import com.ybt.pub.XmlUtil;

public class TaskConfigManager {
    private static Logger logger = Logger.getLogger(TaskConfigManager.class);
    private static String CONFIG_DIR = "conf"
            + File.separator + "taskDefine.xml";
    private Map<TaskType, TaskDefine> map;
    private Map<String, TaskDefine> tags;

    private Map<TaskType, ITaskParser<ITask>> parsers;
    private Map<TaskType, ITaskCompiler<ITask>> compilers;

    private volatile static TaskConfigManager manager;

    private TaskConfigManager() {
        map = new HashMap<TaskType, TaskDefine>();
        tags = new HashMap<String, TaskDefine>();
        parsers = new HashMap<TaskType, ITaskParser<ITask>>();
        compilers = new HashMap<TaskType, ITaskCompiler<ITask>>();
        
        CONFIG_DIR = YBTConfigration.getInstance().getProperty(
                IYBTConfigration.WORKFLOW_DEPLOY_PATH)
                + File.separator + CONFIG_DIR;

        loadFromLocal();
    }

    public static TaskConfigManager getInstance() {
        if (manager == null) {
            synchronized (TaskConfigManager.class) {
                if (manager == null) {
                    manager = new TaskConfigManager();
                }
            }
        }
        return manager;
    }

    /**
     * 根据xml标签tag名，获取工作流节点解析器.
     * 
     * @param tagName
     *            工作流节点tag名
     * @return 工作流节点解析器
     */
    public ITaskParser<ITask> getTaskParser(String tagName) {
        TaskDefine define = tags.get(tagName);
        if (define == null) {
            // tag名不支持
            throw new RuntimeException("unsupport task tag, tagName is = "
                    + tagName);
        }
        return getTaskParser(define.type);
    }

    /**
     * 根据xml标签tag名，初始化ITask对象.
     * @param tagName
     *            工作流节点tag名
     * @return 工作流节点解析器
     */
    public <E extends ITask> E createTask(String tagName) {
        TaskDefine define = tags.get(tagName);
        if (define == null) {
            // tag名不支持
            throw new RuntimeException("unsupport task tag, tagName is = "
                    + tagName);
        }
        
        try {
            // 初始化工作流任务
            Class c = Class.forName(define.implement);
           return (E) c
                    .newInstance();
        } catch (Exception e) {
            throw new RuntimeException(
                    "initialize task error :"
                            + define.implement);
        }
    }
    
    /**
     * 根据工作流任务的类型（TaskType），获取工作流节点解析器.
     * 
     * @param taskType
     *            工作流任务的类型
     * @return 工作流节点解析器
     */
    public ITaskParser<ITask> getTaskParser(TaskType taskType) {
        if (parsers.get(taskType) == null) {
            // 解析器不存在
            synchronized (parsers) {
                if (parsers.get(taskType) == null) {
                    TaskDefine define = this.map.get(taskType);
                    if (define == null) {
                        throw new RuntimeException(
                                "unsupport TaskParser, type is =" + taskType);
                    } else {
                        // 解析器第一次使用
                        logger.debug("loading the task parser :"
                                + define.parser);
                        try {
                            // 初始化解析器
                            Class c = Class.forName(define.parser);
                            ITaskParser<ITask> p = (ITaskParser<ITask>) c
                                    .newInstance();
                            parsers.put(taskType, p);
                        } catch (Exception e) {
                            throw new RuntimeException(
                                    "initialize task parser error :"
                                            + define.parser,e);
                        }
                    }
                }
            }
        }
        return parsers.get(taskType);
    }

    /**
     * 根据工作流任务的类型（TaskType），获取工作流任务编译器.
     * 
     * @param taskType
     *            工作流任务的类型
     * @return 工作流任务编译器
     */
    public ITaskCompiler<ITask> getTaskCompiler(TaskType taskType) {
        if (compilers.get(taskType) == null) {
            // 编译器不存在
            synchronized (compilers) {
                if (compilers.get(taskType) == null) {
                    TaskDefine define = this.map.get(taskType);
                    if (define == null) {
                        throw new RuntimeException(
                                "unsupport task compiler, type is =" + taskType);
                    } else {
                        // 编译器第一次使用
                        logger.debug("loading the task compiler :"
                                + define.compiler);
                        try {
                            // 初始化编译器
                            Class c = Class.forName(define.compiler);
                            ITaskCompiler<ITask> p = (ITaskCompiler<ITask>) c
                                    .newInstance();
                            compilers.put(taskType, p);
                            return p;
                        } catch (Exception e) {
                            throw new RuntimeException(
                                    "initialize task compiler error :"
                                            + define.compiler,e);
                        }
                    }
                }
            }
        }
        return compilers.get(taskType);

    }

    /**
     * 根据xml标签tag名，判断改节点是否是工作流节点. 如果该节点是工作流节点，则返回true；否则返回false
     * 
     * @param tagName
     *            节点tag名
     * @return
     */
    public boolean isWorkflowElement(String tagName) {
        if (tags.get(tagName) != null) {
            return true;
        }
        return false;
    }

    private void loadFromLocal() {

        File file = new File(CONFIG_DIR);
        if (!file.exists()) {
            throw new RuntimeException("can't find the configration file : "
                    + CONFIG_DIR);
        }

        try {
            Document doc = XmlUtil.loadXml(CONFIG_DIR,
                    YBTRuntimeConfiguration.getInstance()
                            .getConfigFileCharset());
            List<Element> tasks = doc.getRootElement().elements("task");
            for (Element et : tasks) {
                String type = et.attributeValue("type");
                String tag = et.element("tag").getTextTrim();
                String impl = et.element("implement").getTextTrim();
                String parser = et.element("parser").getTextTrim();
                String compiler = et.element("compiler").getTextTrim();
                TaskType ttype = TaskType.valueOf(type);
                map.put(ttype, new TaskDefine(ttype, impl, parser, compiler,
                        tag));
                tags.put(tag,
                        new TaskDefine(ttype, impl, parser, compiler, tag));
            }
        } catch (Exception e) {
            throw new RuntimeException("parse configration file error : "
                    + CONFIG_DIR, e);
        }
    }

    private class TaskDefine {
        TaskType type;
        String implement;
        String parser;
        String compiler;
        String tag;

        public TaskDefine(TaskType type, String implement, String parser,
                String compiler, String tag) {
            super();
            this.type = type;
            this.implement = implement;
            this.parser = parser;
            this.compiler = compiler;
            this.tag = tag;
        }
    }
}
